#include "gwlib/gw_dir.h"

#include <json/json.h>
#include <gwbase/base/logging.h>
#include <gwbase/curl_wrapper.h>
#include <gwbase/http_util.h>
#include "gwlib/gw_login.h"

namespace dicom {

int ParseSingleDirEntryResult(const std::string& s, DirEntry* out) {
  Json::Value v;
  Json::Reader r;
  if (!r.parse(s, v, false)) {
    LOG_INFO << "invalid response: " << s;
    return -EIO;
  }

  if (v["code"].asInt() != 0) {
    LOG_INFO << "invalid code in response: " << s;
    int code = v["code"].asInt();
    if (code == 404)
      return -ENOENT;
    return -EIO;
  }

  Json::Value& dir = v["item"];

  out->id = dir["id"].asString();
  out->size = dir["size"].asInt64();
  out->name = dir["name"].asString();
  out->is_folder = (dir["type"] == "folder");
  std::string t = dir["modifiedTime"].asString();
  Timestamp mtime = Timestamp::FromISO8601(t);
  out->mtime = mtime.ToTimeT();
  return 0;
}

int CreateDir(GwToken* t,
              const std::string& pid,
              const std::string& name,
              DirEntry* out)
{
  EasyCurl curl;

  CurlHeaders headers;
  headers.AddOAuthHeader(t->token);
  curl.AddHeaders(&headers);

  std::string url = t->server + "/api/folder/create?";
  AppendQueryString(&url, "pid", pid);
  AppendQueryString(&url, "name", name);
  curl.SetUrl(url);

  std::string response;
  curl.EnableDebugOutput(true);
  bool ok = curl.PerformText(&response);
  if (!ok || curl.http_status() != 200)
    return -1;

  return ParseSingleDirEntryResult(response, out);
}

int RenameDir(GwToken* t,
              const std::string& id,
              const std::string& new_name,
              DirEntry* out)
{
  EasyCurl curl;

  CurlHeaders headers;
  headers.AddOAuthHeader(t->token);
  curl.AddHeaders(&headers);

  std::string url = t->server + "/api/folder/rename?";
  AppendQueryString(&url, "id", id);
  AppendQueryString(&url, "name", new_name);
  curl.SetUrl(url);

  std::string response;
  curl.EnableDebugOutput(true);
  bool ok = curl.PerformText(&response);
  if (!ok || curl.http_status() != 200)
    return -1;

  return ParseSingleDirEntryResult(response, out);
}


int DeleteDir(GwToken* t,
              const std::string& id)
{
  EasyCurl curl;

  CurlHeaders headers;
  headers.AddOAuthHeader(t->token);
  curl.AddHeaders(&headers);

  std::string url = t->server + "/api/folder/delete?";
  AppendQueryString(&url, "id", id);
  curl.SetUrl(url);

  std::string response;
  curl.EnableDebugOutput(true);
  bool ok = curl.PerformText(&response);
  if (!ok || curl.http_status() != 200)
    return -1;

  Json::Reader r;
  Json::Value v;
  if (r.parse(response, v, false) == false)
    return -1;

  if (v["code"].asInt() != 0)
    return -1;

  return 0;
}

int Lookup(GwToken* t, 
           const std::string& pid,
           const std::string& name,
           DirEntry* out)
{
  EasyCurl curl;

  CurlHeaders headers;
  headers.AddOAuthHeader(t->token);
  curl.AddHeaders(&headers);

  std::string url = t->server + "/api/folder/lookup?";
  AppendQueryString(&url, "pid", pid);
  AppendQueryString(&url, "name", name);
  curl.SetUrl(url);

  std::string response;
  curl.EnableDebugOutput(true);
  bool ok = curl.PerformText(&response);
  if (!ok || curl.http_status() != 200)
    return -1;

  return ParseSingleDirEntryResult(response, out);
}

static bool ParseDirEntryList(const std::string& s, DirEntryList* out) {
  Json::Value v;
  Json::Reader r;
  if (!r.parse(s, v, false))
    return false;

  if (v["code"].asInt() != 0)
    return false;

  const Json::Value& items = v["items"];

  for (unsigned int i = 0; i < items.size(); ++i) {
    DirEntry de;
    const Json::Value& it = items[i];
    de.id = it["id"].asString();
    de.size = it["size"].asInt64();
    de.name = it["name"].asString();
    de.is_folder = (it["type"].asString() == "folder");
    Timestamp mtime = 
        Timestamp::FromISO8601(it["modifiedTime"].asString());
    de.mtime = mtime.ToTimeT();
    out->push_back(de);
  }

  return true;
}

int ReadDir(GwToken* t, 
            const std::string& pid,
            DirEntryList* items)
{
  EasyCurl curl;
  CurlHeaders headers;
  headers.AddOAuthHeader(t->token);
  curl.AddHeaders(&headers);

  std::string url = t->server + "/api/folder/readdir?";
  AppendQueryString(&url, "pid", pid);
  curl.SetUrl(url);

  curl.EnableDebugOutput(true);

  std::string response;
  bool ok = curl.PerformText(&response);
  if (!ok || curl.http_status() != 200)
    return -1;

  if (!ParseDirEntryList(response, items))
    return -1;

  return 0;
}

};
